package sdk

import (
	"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
	"github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager"
	"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl"
)

type ChanCode struct {
	mgmtCli    *resmgmt.Client
	channelCli *channel.Client
	channelId  string
	goPath     string
	ccPath     string
	ccId       string
}

/*
	安装链码
 */
func (m *ChanCode) Install(version string) error {
	ccPkg, err := gopackager.NewCCPackage(m.ccPath, m.goPath)
	if err != nil {
		return err
	}
	installCCReq := resmgmt.InstallCCRequest{Name: m.ccId, Path: m.ccPath, Version: version, Package: ccPkg}
	_, err = m.mgmtCli.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
	if err != nil {
		return err
	}
	return nil
}

/*
	初始化链码
 */
func (m *ChanCode) Instantiate(orgMSP []string, version string) error {
	//Org1MSP
	ccPolicy := cauthdsl.SignedByAnyMember(orgMSP)

	req := resmgmt.InstantiateCCRequest{Name: m.ccId, Path: m.ccPath, Version: version, Args: [][]byte{[]byte("init")}, Policy: ccPolicy}
	_, err := m.mgmtCli.InstantiateCC(m.channelId, req)
	if err != nil {
		return err
	}
	return nil
}

func (m *ChanCode) Upgrade(orgMSP []string, version string) error {
	ccPolicy := cauthdsl.SignedByAnyMember(orgMSP)

	req := resmgmt.UpgradeCCRequest{Name: m.ccId, Path: m.ccPath, Version: version, Args: [][]byte{[]byte("init")}, Policy: ccPolicy}
	_, err := m.mgmtCli.UpgradeCC(m.channelId, req)
	if err != nil {
		return err
	}
	return nil
}

/*
	执行链码
 */
func (m *ChanCode) Execute(fcn string, args [][]byte) (*channel.Response, error) {
	res, err := m.channelCli.Execute(channel.Request{ChaincodeID: m.ccId, Fcn: fcn, Args: args},
		channel.WithRetry(retry.DefaultChannelOpts),
	)
	if err != nil {
		return nil, err
	}
	return &res, nil
}

/*
	查询链码
 */
func (m *ChanCode) Query(fcn string, args [][]byte) (*channel.Response, error) {
	res, err := m.channelCli.Query(channel.Request{ChaincodeID: m.ccId, Fcn: fcn, Args: args},
		channel.WithRetry(retry.DefaultChannelOpts),
	)
	if err != nil {
		return nil, err
	}
	return &res, nil
}
